#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "record.h"
#include "control.h"

#include "config.h"
#include "token.h"
#include "http.h"

#define GPIO_LINE_KEY1 9
#define GPIO_LINE_KEY2 7
#define GPIO_LINE_KEY3 8

char *app_id = "62b84ef5-5daf-491d-97a8-5966fb4deb34";

// 创建会话
char *create_conversation(char *authtoken)
{
    char *url = "https://qianfan.baidubce.com/v2/app/conversation";

    // 拼接Authorization字段
    char *auth;
    asprintf(&auth, "Authorization: Bearer %s", authtoken);

    // 添加请求头部字段
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: application/json;charset=utf-8");
    headers = curl_slist_append(headers, auth);

    // 准备请求正文
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddStringToObject(obj, "app_id", app_id);
    // 将JSON对象转换为JSON字符串
    char *json = cJSON_Print(obj);

    // 发送请求
    size_t size = strlen(json);
    char *response = post(url, headers, json, &size);
    cJSON_Delete(obj);
    free(json);
    free(auth);
    curl_slist_free_all(headers);

    if (!response)
    {
        return NULL;
    }

    obj = cJSON_ParseWithLength(response, size);
    free(response);

    if (!obj)
    {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    cJSON *conversation_id = cJSON_GetObjectItem(obj, "conversation_id");
    if (!conversation_id)
    {
        fprintf(stderr, "conversation_id 字段不存在\n");
        cJSON_Delete(obj);
        return NULL;
    }

    char *retval = strdup(conversation_id->valuestring);

    cJSON_Delete(obj);

    return retval;
}

// 调用对话API
// authtoken: 平台密钥
// conv_id: 会话ID
// query: 用户输入的文本
// 返回值: 对话结果
char *chat(char *authtoken, char *conv_id, char *query)
{
    char *url = "https://qianfan.baidubce.com/v2/app/conversation/runs";

    // 拼接Authorization字段
    char *auth;
    asprintf(&auth, "Authorization: Bearer %s", authtoken);

    // 设置请求头部字段
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: application/json;charset=utf-8");
    headers = curl_slist_append(headers, auth);

    // 准备请求正文
    cJSON *obj = cJSON_CreateObject();
    cJSON_AddStringToObject(obj, "app_id", app_id);
    cJSON_AddStringToObject(obj, "conversation_id", conv_id);
    cJSON_AddStringToObject(obj, "query", query);
    cJSON_AddBoolToObject(obj, "stream", false);
    // 将JSON对象转换为JSON字符串
    char *json = cJSON_Print(obj);

    // 发送请求
    size_t size = strlen(json);
    char *response = post(url, headers, json, &size);
    cJSON_Delete(obj);
    free(json);
    curl_slist_free_all(headers);
    free(auth);

    if (!response)
    {
        return NULL;
    }

    obj = cJSON_ParseWithLength(response, size);
    free(response);

    if (!obj)
    {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    cJSON *answer = cJSON_GetObjectItem(obj, "answer");
    if (!answer)
    {
        fprintf(stderr, "answer 字段不存在\n");
        puts(cJSON_Print(obj));
        cJSON_Delete(obj);
        return NULL;
    }

    char *retval = strdup(answer->valuestring);

    cJSON_Delete(obj);

    return retval;
}

// 读取音频文件
// file: 音频文件路径
// size: 音频文件大小
// return: 音频文件内容, NULL 表示失败
char *load_audio_file(const char *file, size_t *size)
{
    // 打开音频文件
    FILE *fp = fopen(file, "rb");
    if (!fp)
    {
        perror(file);
        return NULL;
    }
    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    *size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    // 读取文件内容
    char *buffer = (char *)malloc(*size);
    if (!buffer)
    {
        perror("malloc");
        fclose(fp);
        return NULL;
    }
    fread(buffer, 1, *size, fp);
    fclose(fp);
    return buffer;
}

// 发送请求消息
// token: 获取的access token
// audio: 音频文件内容
// size: 音频文件大小
// return: 响应消息正文, NULL 表示失败
char *send_request(char *token, char *audio, size_t size)
{
    char *url = NULL;
    asprintf(&url, "http://vop.baidu.com/server_api?cuid=hqyj&token=%s", token);

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: audio/pcm; rate=16000");

    char *response = post(url, headers, audio, &size);

    free(url);
    curl_slist_free_all(headers);

    return response;
}

// 处理服务器返回的响应消息
char *process_response(char *response, size_t size)
{
    // 解析 JSON 响应
    cJSON *json = cJSON_ParseWithLength(response, size);
    if (!json)
    {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return NULL;
    }

    // 判断err_no字段
    cJSON *err_no = cJSON_GetObjectItem(json, "err_no");
    if (!err_no)
    {
        fprintf(stderr, "err_no 字段不存在\n");
        cJSON_Delete(json);
        return NULL;
    }

    // 判断err_no的值
    if (err_no->valueint != 0)
    {
        // 打印错误信息
        cJSON *err_msg = cJSON_GetObjectItem(json, "err_msg");
        if (err_msg)
        {
            fprintf(stderr, "err_msg: %s\n", err_msg->valuestring);
        }
        cJSON_Delete(json);
        return NULL;
    }

    // 获取 "result" 字段中的第一个元素
    cJSON *result = cJSON_GetObjectItem(json, "result");
    if (!result)
    {
        fprintf(stderr, "JSON 格式错误: 找不到'result' 字段\n");
        cJSON_Delete(json);
        return NULL;
    }

    if (cJSON_GetArraySize(result) > 0)
    {
        // 获取第一个元素的 "content" 字段
        cJSON *content = cJSON_GetArrayItem(result, 0);
        if (content && cJSON_IsString(content))
        {
            // 分配内存并返回字符串
            char *content_str = strdup(content->valuestring);
            cJSON_Delete(json);
            return content_str;
        }
    }

    // 释放 JSON 对象
    cJSON_Delete(json);
    return NULL;
}

int main(void)
{
    struct gpiod_chip *chip;
    struct gpiod_line *line_key1, *line_key2, *line_key3;
    int value_key1, last_value_key1;
    int value_key2, last_value_key2;
    int value_key3, last_value_key3;

    snd_pcm_uframes_t period = 999; // 周期大小
    snd_pcm_t *capture;             // 音频采集设备
    char *buffer = NULL;            // 存放音频数据的缓冲区
    FILE *fp = NULL;                // 录音文件

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip)
    {
        perror("打开GPIO芯片失败");
        return 1;
    }

    // 获取GPIO线
    line_key1 = gpiod_chip_get_line(chip, GPIO_LINE_KEY1);
    line_key2 = gpiod_chip_get_line(chip, GPIO_LINE_KEY2);
    line_key3 = gpiod_chip_get_line(chip, GPIO_LINE_KEY3);
    if (!line_key1 || !line_key2 || !line_key3)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 将GPIO线设置为输入模式
    if (gpiod_line_request_input(line_key1, "key1") ||
        gpiod_line_request_input(line_key2, "key2") ||
        gpiod_line_request_input(line_key3, "key3"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 获取初始的GPIO线值
    last_value_key1 = gpiod_line_get_value(line_key1);
    last_value_key2 = gpiod_line_get_value(line_key2);
    last_value_key3 = gpiod_line_get_value(line_key3);

    // 无限循环检测GPIO线值的变化
    while (1)
    {
        // 获取当前的GPIO线值
        value_key1 = gpiod_line_get_value(line_key1);
        value_key2 = gpiod_line_get_value(line_key2);
        value_key3 = gpiod_line_get_value(line_key3);

        if (value_key1 != last_value_key1)
        {
            // 如果当前值为0，表示按键被按下
            if (value_key1 == 0)
            {
                printf("key pressed\n");
                capture = record_open("hw:0,1", SND_PCM_FORMAT_S16_LE, 1, 16000, &period);
                if (!capture)
                {
                    continue;
                }
                buffer = malloc(snd_pcm_frames_to_bytes(capture, period)); // 分配缓冲区
                if (!buffer)
                {
                    perror("malloc");
                    record_close(capture);
                    continue;
                }

                fp = fopen("output.pcm", "wb");
                if (!fp)
                {
                    perror("Error opening output file");
                    free(buffer);          // 释放缓冲区
                    record_close(capture); // 关闭PCM设备
                    continue;
                }
            }
            // 如果当前值为1，表示按键被释放
            else
            {
                printf("key released\n");
                record_close(capture);
                capture = NULL;

                // 读取音频文件
                size_t size;
                char *buffer = load_audio_file("output.pcm", &size);
                if (!buffer)
                {
                    return EXIT_FAILURE;
                }

                // 读取配置信息，API KEY 和 SECRET KEY
                cJSON *config = read_config("config.json");
                if (!config)
                {
                    printf("config: %s\n", cJSON_Print(config));
                    free(buffer);
                    return EXIT_FAILURE;
                }
                cJSON *api_key = cJSON_GetObjectItem(config, "api_key");
                cJSON *secret_key = cJSON_GetObjectItem(config, "secret_key");
                cJSON *authtoken = cJSON_GetObjectItem(config, "authtoken");
                if (!api_key || !secret_key || !authtoken)
                {
                    fprintf(stderr, "配置文件错误: 找不到 'api_key' 或'secret_key'或'authtoken'字段\n");
                    cJSON_Delete(config);
                    free(buffer);
                    return EXIT_FAILURE;
                }
                // 获取token
                char *token = get_access_token(api_key->valuestring, secret_key->valuestring);

                if (!token)
                {
                    fprintf(stderr, "获取 token 失败\n");
                    free(buffer);
                    return EXIT_FAILURE;
                }

                // 调用百度语音识别 API
                char *response = send_request(token, buffer, size);
                free(buffer);
                free(token);
                if (!response)
                {
                    fprintf(stderr, "调用百度语音识别 API 失败\n");
                    return EXIT_FAILURE;
                }
                // 处理服务器返回的响应消息
                char *text = process_response(response, size);
                printf(">%s\n", text);
                printf("authtoken:%s\n", authtoken->valuestring);
                // 创建会话
                char *conv_id = create_conversation(authtoken->valuestring);
                printf("conv_id: %s\n", conv_id);
                char *answer = chat(authtoken->valuestring, conv_id, text);
                printf("< %s\n", answer);

                cJSON_Delete(config);
                free(response);
            }
            // 更新上一次的值为当前值
            last_value_key1 = value_key1;
        }

        if (value_key1 == 0 && capture)
        {
            // 如果按键按下并且音频采集设备已打开
            snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period); // 从PCM设备读取数据
            if (frames < 0)
            {
                fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
                snd_pcm_recover(capture, frames, 0);
            }

            fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, fp); // 将读取的数据写入文件
        }

        // 检测key2的变化
        if (value_key2 != last_value_key2)
        {
            if (value_key2 == 0)
            {
                printf("key2 pressed\n");
            }
            else
            {
                long volume = get_playback_volume("hw:0", "Analog");
                volume += 5;
                set_playback_volume("hw:0", "Analog", volume);
                printf("Volume increased to %ld\n", volume);
            }
            last_value_key2 = value_key2;
        }

        // 检测key3的变化
        if (value_key3 != last_value_key3)
        {
            if (value_key3 == 0)
            {
                printf("key3 pressed\n");
            }
            else
            {
                long volume = get_playback_volume("hw:0", "Analog");
                volume -= 5;
                set_playback_volume("hw:0", "Analog", volume);
                printf("Volume decreased to %ld\n", volume);
            }
            last_value_key3 = value_key3;
        }

        // 延时100毫秒，防止检测过于频繁
        // usleep(100000);
    }

    // 关闭GPIO芯片
    gpiod_chip_close(chip);
    return 0;
}
